//
// Created by mayunxi on 2020/6/11.
//

#include "Decoder4CPU.h"
/************************************************************************
**函数：Decoder4CPU
**功能：编解码初始化，申请资源
**参数：
       void
**返回：
       true成功，false失败
**备注：
************************************************************************/
bool Decoder4CPU::init()
{

    FreeResource();
    //char m_channel_set.rtsp_url[]="rtsp://218.204.223.237:554/live/1/0547424F573B085C/gsfp90ef4k0a6iap.sdp";
    //char m_channel_set.rtsp_url[]="rtsp://admin:labtest123@192.168.20.200:554/h264/main/av_stream";
    //char m_channel_set.rtsp_url[]="rtsp://admin:labtest123@192.168.200.185/media/video1/multicast";
//Allocate an AVFormatContext.
    m_input_avfmt_ctx = avformat_alloc_context();//申请一个AVFormatContext结构的内存,并进行简单初始化
    m_input_avfmt_ctx->interrupt_callback.callback = interrupt_callback;
    m_input_avfmt_ctx->interrupt_callback.opaque = &m_input_runner;

    m_input_runner.lasttime = time(NULL);
    av_dict_set(&m_opts, "rtsp_transport",  "tcp", 0); //rtsp默认采用UDP,容易丢包，造成花屏，这里改为TCP
    //开流超时设计
    av_dict_set(&m_opts, "stimeout", "3000000", 0);//单位us 也就是这里设置的是3s
    av_dict_set(&m_opts, "rw_timeout", "3000", 0);//单位:ms

    //https://gitee.com/mayunxi52/video_coder/issues/I1QTJA
    int ret=avformat_open_input(&m_input_avfmt_ctx, m_channel_set.rtsp_url.c_str(),nullptr,&m_opts);
    if (ret<0){
        m_msg = m_rtsp_info.ip +",can't open video stream,"+g_ffmpeg_err;
        LOG4CPLUS_ERROR(g_logger,m_msg);
        //cout << m_rtsp_info.ip <<",打开视频流失败" << endl;
        return false;
    }

    //获取视频流信息
    ret=avformat_find_stream_info(m_input_avfmt_ctx,nullptr);
    if (ret<0){
        m_msg = m_rtsp_info.ip +",can't get stream info,"+g_ffmpeg_err;
       // LOG4CPLUS_ERROR(g_logger,m_msg);
        return false;
    }

    //获取视频流索引
    for (int i = 0; i < m_input_avfmt_ctx->nb_streams; i++) {
        if (m_input_avfmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            m_video_stream_index = i;
            break;
        }
    }

    if (m_video_stream_index == -1){
        m_msg = m_rtsp_info.ip +",can't get stream index,"+g_ffmpeg_err;
        //LOG4CPLUS_ERROR(g_logger,m_msg);
        return false;
    }

    //获取编解码器上下文，指向m_input_avfmt_ctx中的AVCodecContext
    m_decoder_ctx = m_input_avfmt_ctx->streams[m_video_stream_index]->codec;
    AVRational fps_avrational = m_input_avfmt_ctx->streams[m_video_stream_index]->avg_frame_rate; //帧率
    if (fps_avrational.den != 0)
    {
        m_fps = fps_avrational.num / fps_avrational.den;
    }
    //set decoder as low deday
    m_decoder_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
    //获取视频流的分辨率大小
    m_video_width=m_decoder_ctx->width;
    m_video_height=m_decoder_ctx->height;

    //获取视频流解码器

    m_avcodec = avcodec_find_decoder(m_decoder_ctx->codec_id);

    //打开对应解码器
    ret=avcodec_open2(m_decoder_ctx,m_avcodec,NULL);
    if (ret<0){
        m_msg = m_rtsp_info.ip +",can't open codec,"+g_ffmpeg_err;
        //LOG4CPLUS_ERROR(g_logger,m_msg);
        return false;
    }

    //avpicture_alloc(&pAVPicture,AV_PIX_FMT_RGB24,m_video_width,m_video_height);

    m_avframe=av_frame_alloc();
    //Output Info-----------------------------
    printf("---------------- File Information ---------------\n");
    av_dump_format(m_input_avfmt_ctx, 0, m_channel_set.rtsp_url.c_str(), 0);
    printf("-------------------------------------------------\n");
    //LOG4CPLUS_INFO(g_logger,m_rtsp_info.ip  + " init stream succussfully:"+  to_string(m_video_width) + "x" + to_string(m_video_height) +","+to_string(m_fps));
    DisplayInit(m_video_width, m_video_height);
    //yuvj420p to yuv420p
   
    m_pFrameYUV = av_frame_alloc();
    m_out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, m_video_width, m_video_height, 1));
    av_image_fill_arrays(m_pFrameYUV->data, m_pFrameYUV->linesize, m_out_buffer,
        AV_PIX_FMT_YUV420P, m_video_width, m_video_height, 1);

    m_img_convert_ctx = sws_getContext(m_video_width, m_video_height, m_decoder_ctx->pix_fmt,
        m_video_width, m_video_height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

    HANDLE hThread = CreateThread(NULL, 0, StartFunc, (void*)this, 0, NULL);
    return true;

}
DWORD WINAPI Decoder4CPU::StartFunc(void* Param)
{
    Decoder4CPU* ptr = (Decoder4CPU*)Param;
    ptr->GetPicture();
    return 0;
}
int Decoder4CPU::GetPicture()
{
    
    int ret, got_picture;
    static int failedCount = 0;
    AVPacket* packet;
    while (1)
    {
        m_input_runner.lasttime = time(NULL);
        if (m_input_avfmt_ctx != NULL)     //long time is connected,the AVFormatContext will be setted to null
        {
            packet = av_packet_alloc();
            //获取一帧压缩数据，如h.264
            if (av_read_frame(m_input_avfmt_ctx, packet) < 0)
            {
                av_packet_free(&packet); //释放资源,否则内存会一直上升
                failedCount++;
                if (failedCount > 3)
                {
                    m_msg = m_rtsp_info.ip + ",no get a packet," + g_ffmpeg_err;;
                    //LOG4CPLUS_ERROR(g_logger,m_msg );
                    m_err_code = "2301103";
                    failedCount = 0;
                    this->init();
                }

                return -1;
            }
        }
        else
        {
            //连接时ipc网络断开
            failedCount++;
            if (failedCount > (10 * 1000000 / SLEEP_US))
            {
                m_msg = m_rtsp_info.ip + ",AVFormatContext is null,will reconnenct," + g_ffmpeg_err;;
                //LOG4CPLUS_ERROR(g_logger, m_msg);
                m_err_code = "2301103";
                failedCount = 0;
                this->init();
            }
            return -1;
        }
        m_frame_num++;


        if (m_video_width != m_decoder_ctx->width || m_video_height != m_decoder_ctx->height) {
            m_video_width = m_decoder_ctx->width;
            m_video_height = m_decoder_ctx->height;
            //LOG4CPLUS_INFO(g_logger,m_rtsp_info.ip  + " w*h have changed to"+  to_string(m_video_width) + "x" + to_string(m_video_height));
        }

        //Wait
        SDL_WaitEvent(&m_event);
        if (m_event.type == SFM_REFRESH_EVENT) {
        
            ret = avcodec_decode_video2(m_decoder_ctx, m_avframe, &got_picture, packet);
            if (ret < 0) {
                printf("Decode Error.\n");
                return -1;
            }
            if (got_picture) {
                sws_scale(m_img_convert_ctx, (const unsigned char* const*)m_avframe->data, m_avframe->linesize, 0, m_video_height, m_pFrameYUV->data, m_pFrameYUV->linesize);
                Display(m_pFrameYUV);
            }
            av_free_packet(packet);
        }
        else if (m_event.type == SDL_KEYDOWN) {
            //Pause
            if (m_event.key.keysym.sym == SDLK_SPACE)
                m_thread_pause = !m_thread_pause;
        }
        else if (m_event.type == SDL_QUIT) {
            m_thread_exit = 1;
        }
        else if (m_event.type == SFM_BREAK_EVENT) {
            break;
        }
        av_packet_free(&packet); //释放资源,否则内存会一直上升
    }
  

    return 0;

}



